using GroupSix.Domain.Entity.App;
using GroupSix.Domain.Repositories;
using GroupSix.Application.Dtos;
using GroupSix.Domain.common;

namespace GroupSix.Application.Services;

/// <summary>
/// 菜单服务
/// </summary>
public class MenuService
{
    private readonly IMenuRepository _menuRepository;

    public MenuService(IMenuRepository menuRepository)
    {
        _menuRepository = menuRepository;
    }

    /// <summary>
    /// 创建菜单
    /// </summary>
    /// <param name="request">创建菜单请求</param>
    /// <returns>创建结果</returns>
    public async Task<(bool success, string message, MenuResponseDto? data)> CreateAsync(CreateMenuRequestDto request)
    {
        try
        {
            // 验证菜单名称唯一性
            if (await _menuRepository.IsMenunameExistsAsync(request.Menuname))
            {
                return (false, "菜单名称已存在", null);
            }

            // 验证菜单路径唯一性（如果提供了路径）
            if (!string.IsNullOrEmpty(request.MenuPath) && await _menuRepository.IsMenuPathExistsAsync(request.MenuPath))
            {
                return (false, "菜单路径已存在", null);
            }

            // 验证父菜单是否存在（如果指定了父菜单）
            if (request.ParentId.HasValue)
            {
                var parentMenu = await _menuRepository.GetByIdAsync(request.ParentId.Value);
                if (parentMenu == null)
                {
                    return (false, "父菜单不存在", null);
                }
            }

            // 如果没有指定排序，自动设置为同级菜单的最大排序值+1
            if (request.Order == 0)
            {
                request.Order = await _menuRepository.GetMaxOrderAsync(request.ParentId) + 1;
            }

            // 创建菜单实体
            var menu = new GsMenu(
                request.Menuname,
                request.MenuPath,
                request.MenuIcon,
                request.ParentId,
                request.Order,
                request.PermissionKey
            );

            // 保存到数据库
            await _menuRepository.CreateAsync(menu);

            // 返回创建结果
            var response = new MenuResponseDto
            {
                Id = menu.Id,
                Menuname = menu.Menuname,
                MenuPath = menu.MenuPath,
                MenuIcon = menu.MenuIcon,
                ParentId = menu.ParentId,
                Order = menu.Order,
                PermissionKey = menu.PermissionKey,
                CreatedAt = menu.CreatedAt,
                UpdatedAt = menu.UpdatedAt
            };

            return (true, "菜单创建成功", response);
        }
        catch (Exception ex)
        {
            return (false, $"创建菜单失败: {ex.Message}", null);
        }
    }

    /// <summary>
    /// 更新菜单
    /// </summary>
    /// <param name="request">更新菜单请求</param>
    /// <returns>更新结果</returns>
    public async Task<(bool success, string message)> UpdateAsync(UpdateMenuRequestDto request)
    {
        try
        {
            // 获取菜单
            var menu = await _menuRepository.GetByIdAsync(request.Id);
            if (menu == null)
            {
                return (false, "菜单不存在");
            }

            // 验证菜单名称唯一性（排除当前菜单）
            if (await _menuRepository.IsMenunameExistsAsync(request.Menuname, request.Id))
            {
                return (false, "菜单名称已存在");
            }

            // 验证菜单路径唯一性（排除当前菜单）
            if (!string.IsNullOrEmpty(request.MenuPath) && await _menuRepository.IsMenuPathExistsAsync(request.MenuPath, request.Id))
            {
                return (false, "菜单路径已存在");
            }

            // 验证父菜单是否存在（如果指定了父菜单）
            if (request.ParentId.HasValue)
            {
                // 不能将自己设为父菜单
                if (request.ParentId.Value == request.Id)
                {
                    return (false, "不能将自己设为父菜单");
                }

                var parentMenu = await _menuRepository.GetByIdAsync(request.ParentId.Value);
                if (parentMenu == null)
                {
                    return (false, "父菜单不存在");
                }

                // 检查是否形成循环引用
                if (await IsCircularReference(request.Id, request.ParentId.Value))
                {
                    return (false, "不能将子菜单设为父菜单，避免循环引用");
                }
            }

            // 更新菜单信息
            menu.UpdateInfo(
                request.Menuname,
                request.MenuPath,
                request.MenuIcon,
                request.ParentId,
                request.Order,
                request.PermissionKey
            );

            // 保存到数据库
            await _menuRepository.UpdateAsync(menu);

            return (true, "菜单更新成功");
        }
        catch (Exception ex)
        {
            return (false, $"更新菜单失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 删除菜单
    /// </summary>
    /// <param name="id">菜单ID</param>
    /// <returns>删除结果</returns>
    public async Task<(bool success, string message)> DeleteAsync(Guid id)
    {
        try
        {
            // 获取菜单
            var menu = await _menuRepository.GetByIdAsync(id);
            if (menu == null)
            {
                return (false, "菜单不存在");
            }

            // 检查是否有子菜单
            if (await _menuRepository.HasChildrenAsync(id))
            {
                return (false, "菜单下有子菜单，无法删除");
            }

            // 检查是否被角色使用
            if (await _menuRepository.IsUsedByRolesAsync(id))
            {
                var roleCount = await _menuRepository.GetRoleCountAsync(id);
                return (false, $"菜单正在被{roleCount}个角色使用，无法删除");
            }

            // 删除菜单
            await _menuRepository.DeleteAsync(id);

            return (true, "菜单删除成功");
        }
        catch (Exception ex)
        {
            return (false, $"删除菜单失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 获取菜单列表
    /// </summary>
    /// <param name="request">请求参数</param>
    /// <returns>菜单列表</returns>
    public async Task<(bool success, string message, MenuListResponseDto? data)> GetListAsync(GetMenusRequestDto request)
    {
        try
        {
            // 获取分页数据
            var pageResult = await _menuRepository.GetPagedAsync(
                request.PageIndex,
                request.PageSize,
                request.Menuname,
                request.MenuPath,
                request.ParentId
            );

            // 获取菜单树
            var menuTree = await _menuRepository.GetMenuTreeAsync();

            // 转换为DTO
            var menuTreeDto = ConvertToMenuTreeDto(menuTree);

            var response = new MenuListResponseDto
            {
                MenuTree = menuTreeDto,
                TotalCount = pageResult.TotalCount
            };

            return (true, "获取菜单列表成功", response);
        }
        catch (Exception ex)
        {
            return (false, $"获取菜单列表失败: {ex.Message}", null);
        }
    }

    /// <summary>
    /// 获取菜单详情
    /// </summary>
    /// <param name="id">菜单ID</param>
    /// <returns>菜单详情</returns>
    public async Task<(bool success, string message, MenuResponseDto? data)> GetByIdAsync(Guid id)
    {
        try
        {
            var menu = await _menuRepository.GetByIdAsync(id);
            if (menu == null)
            {
                return (false, "菜单不存在", null);
            }

            var response = new MenuResponseDto
            {
                Id = menu.Id,
                Menuname = menu.Menuname,
                MenuPath = menu.MenuPath,
                MenuIcon = menu.MenuIcon,
                ParentId = menu.ParentId,
                Order = menu.Order,
                PermissionKey = menu.PermissionKey,
                CreatedAt = menu.CreatedAt,
                UpdatedAt = menu.UpdatedAt
            };

            return (true, "获取菜单详情成功", response);
        }
        catch (Exception ex)
        {
            return (false, $"获取菜单详情失败: {ex.Message}", null);
        }
    }

    /// <summary>
    /// 调整菜单顺序
    /// </summary>
    /// <param name="request">调整顺序请求</param>
    /// <returns>调整结果</returns>
    public async Task<(bool success, string message)> UpdateOrderAsync(UpdateMenuOrderRequestDto request)
    {
        try
        {
            // 获取菜单
            var menu = await _menuRepository.GetByIdAsync(request.Id);
            if (menu == null)
            {
                return (false, "菜单不存在");
            }

            // 更新排序
            var success = await _menuRepository.UpdateOrderAsync(request.Id, request.Order);
            if (!success)
            {
                return (false, "更新菜单排序失败");
            }

            return (true, "菜单排序更新成功");
        }
        catch (Exception ex)
        {
            return (false, $"更新菜单排序失败: {ex.Message}");
        }
    }

    /// <summary>
    /// 获取菜单树
    /// </summary>
    /// <returns>菜单树</returns>
    public async Task<(bool success, string message, List<MenuTreeNodeDto>? data)> GetMenuTreeAsync()
    {
        try
        {
            var menuTree = await _menuRepository.GetMenuTreeAsync();
            var menuTreeDto = ConvertToMenuTreeDto(menuTree);

            return (true, "获取菜单树成功", menuTreeDto);
        }
        catch (Exception ex)
        {
            return (false, $"获取菜单树失败: {ex.Message}", null);
        }
    }

    /// <summary>
    /// 检查循环引用
    /// </summary>
    /// <param name="menuId">菜单ID</param>
    /// <param name="newParentId">新的父菜单ID</param>
    /// <returns>是否形成循环引用</returns>
    private async Task<bool> IsCircularReference(Guid menuId, Guid newParentId)
    {
        var currentParentId = newParentId;
        var visited = new HashSet<Guid> { menuId };

        while (currentParentId != Guid.Empty)
        {
            if (visited.Contains(currentParentId))
            {
                return true; // 发现循环引用
            }

            visited.Add(currentParentId);
            var parentMenu = await _menuRepository.GetByIdAsync(currentParentId);
            if (parentMenu == null)
            {
                break;
            }

            currentParentId = parentMenu.ParentId ?? Guid.Empty;
        }

        return false;
    }

    /// <summary>
    /// 转换为菜单树DTO
    /// </summary>
    /// <param name="menus">菜单列表</param>
    /// <returns>菜单树DTO</returns>
    private List<MenuTreeNodeDto> ConvertToMenuTreeDto(List<GsMenu> menus)
    {
        var menuDict = menus.ToDictionary(m => m.Id);
        var rootMenus = new List<MenuTreeNodeDto>();

        foreach (var menu in menus.OrderBy(m => m.Order))
        {
            var menuDto = new MenuTreeNodeDto
            {
                Id = menu.Id,
                Menuname = menu.Menuname,
                MenuPath = menu.MenuPath,
                MenuIcon = menu.MenuIcon,
                ParentId = menu.ParentId,
                Order = menu.Order,
                PermissionKey = menu.PermissionKey
            };

            if (menu.ParentId == null)
            {
                // 根菜单
                rootMenus.Add(menuDto);
            }
            else if (menuDict.ContainsKey(menu.ParentId.Value))
            {
                // 子菜单
                var parentDto = FindMenuInTree(rootMenus, menu.ParentId.Value);
                if (parentDto != null)
                {
                    parentDto.Children.Add(menuDto);
                }
            }
        }

        return rootMenus;
    }

    /// <summary>
    /// 在菜单树中查找指定ID的菜单
    /// </summary>
    /// <param name="menuTree">菜单树</param>
    /// <param name="menuId">菜单ID</param>
    /// <returns>菜单节点</returns>
    private MenuTreeNodeDto? FindMenuInTree(List<MenuTreeNodeDto> menuTree, Guid menuId)
    {
        foreach (var menu in menuTree)
        {
            if (menu.Id == menuId)
            {
                return menu;
            }

            var found = FindMenuInTree(menu.Children, menuId);
            if (found != null)
            {
                return found;
            }
        }

        return null;
    }
} 